package top.mcwebsite.playandroid.business.search.impl.vm

import android.content.Context
import android.util.Log
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.cachedIn
import kotlinx.coroutines.launch
import top.mcwebsite.playandroid.business.search.impl.api.SearchApi
import top.mcwebsite.playandroid.business.search.impl.model.SearchHistoryData
import top.mcwebsite.playandroid.business.search.impl.model.SearchHistoryKey
import top.mcwebsite.playandroid.business.search.impl.model.SearchResultModel
import top.mcwebsite.playandroid.business.search.impl.repository.searchHistoryDataStore
import top.mcwebsite.playandroid.common.api.AppService
import top.mcwebsite.playandroid.common.network.api.NetworkService
import top.mcwebsite.playandroid.common.network.api.createApi
import top.mcwebsite.playandroid.common.network.model.ApiResult
import top.mcwebsite.playandroid.lib.mvi.base.BaseViewModel
import top.mcwebsite.playandroid.lib.mvi.model.Async
import top.mcwebsite.playandroid.lib.servicemanager.core.ServiceManager

class SearchViewModel : BaseViewModel<SearchIntent, SearchUiState, SearchUiEffect>(SearchUiState()) {

    companion object {
        const val MAX_SEARCH_HISTORY_COUNT = 10
    }

    private val searchApi: SearchApi by lazy {
        ServiceManager.getService<NetworkService>().createApi()
    }

    private val searchHistoryDataStore = ServiceManager.getService<AppService>()
        .getApplication().searchHistoryDataStore

    private val pagingConfig = PagingConfig(pageSize = 10)

    init {
        fetchHotSearchKey()
        fetchHistoryData()
    }


    private fun fetchHistoryData() {
        viewModelScope.launch {
            searchHistoryDataStore.data.collect {
                setUiState {
                    copy(searchHistoryData = it.searchHistoryKeysList)
                }
            }
        }
    }

    override fun handleIntent(intent: SearchIntent) {
        when (intent) {
            is SearchIntent.UpdateSearchKeywordIntent -> {
                setUiState {
                    copy(
                        searchKeyword = intent.keyword,
                        searchResultPagerFlow = if (intent.keyword.isEmpty()) null else searchResultPagerFlow
                    )
                }
            }

            is SearchIntent.SearchActionIntent -> {
                search()
            }

            is SearchIntent.SearchResultItemClickIntent -> {
                sendUiEffect(SearchUiEffect.GoDetailPageUiEffect(intent.searchResultModel))
            }
        }
    }

    private fun fetchHotSearchKey() {
        viewModelScope.launch {
            setUiState { copy(hotSearchKeys = Async.Loading) }
            when (val result = searchApi.hotSearchKey()) {
                is ApiResult.Success -> {
                    setUiState { copy(hotSearchKeys = Async.Success(result.data.data ?: emptyList())) }
                }

                is ApiResult.Failure -> {
                    setUiState { copy(hotSearchKeys = Async.Failed(result.cause.errorMsg, result.cause)) }
                }
            }
        }
    }

    private fun search() {
        setUiState {
            copy(searchResultPagerFlow = Pager(pagingConfig) {
                SearchPagingSource(searchKeyword)
            }.flow.cachedIn(viewModelScope))
        }
        insertSearchHistory(uiState.searchKeyword)
    }

    private fun insertSearchHistory(key: String) {
        viewModelScope.launch {
            val searchHistoryKey = SearchHistoryKey.newBuilder()
                .setKey(key)
                .setTimestamp(System.currentTimeMillis())
                .build()
            searchHistoryDataStore.updateData {
                val historyDataKeys = it.searchHistoryKeysList.filterNot { it.key == key }
                    .toMutableList()
                    .apply { add(searchHistoryKey) }
                    .sortedByDescending { it.timestamp }
                    .take(MAX_SEARCH_HISTORY_COUNT)
                SearchHistoryData.newBuilder()
                    .addAllSearchHistoryKeys(historyDataKeys)
                    .build()
            }
        }
    }

    private inner class SearchPagingSource(
        private val searchKeyword: String,
    ) : PagingSource<Int, SearchResultModel>() {
        override fun getRefreshKey(state: PagingState<Int, SearchResultModel>): Int? {
            return null
        }

        override suspend fun load(params: LoadParams<Int>): LoadResult<Int, SearchResultModel> {
            return try {
                val nextPageNumber = params.key ?: 0
                when (val result = searchApi.search(nextPageNumber, searchKeyword)) {
                    is ApiResult.Success -> {
                        LoadResult.Page(
                            data = result.data.data?.datas ?: emptyList(),
                            prevKey = if (nextPageNumber == 0) null else nextPageNumber - 1,
                            nextKey = if (result.data.data?.over == true) null else nextPageNumber + 1
                        )
                    }

                    is ApiResult.Failure -> {
                        LoadResult.Error(result.cause)
                    }
                }
            } catch (e: Exception) {
                return LoadResult.Error(e)
            }
        }

    }
}